package com.niiwoo.civet.account.service.local.refund;

import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.account.dao.entity.BatchTransOrder;
import com.niiwoo.civet.account.dao.entity.BatchTransOrderDetail;
import com.niiwoo.civet.account.dao.entity.BatchTransOrderDetailBiz;
import com.niiwoo.civet.account.dao.entity.ProTransactionOrder;
import com.niiwoo.civet.account.dao.mapper.BatchTransOrderDetailBizMapperExt;
import com.niiwoo.civet.account.dao.mapper.BatchTransOrderDetailMapperExt;
import com.niiwoo.civet.account.dao.mapper.BatchTransOrderMapperExt;
import com.niiwoo.civet.account.dao.mapper.ProTransactionOrderMapperExt;
import com.niiwoo.civet.account.dto.common.AsyncTransactionNotifyDTO;
import com.niiwoo.civet.account.enums.RefundStatusEnum;
import com.niiwoo.civet.account.service.AccountRefundOrderPushDubboService;
import com.niiwoo.civet.account.service.local.refund.newRefund.CallBackRefundLocalService;
import com.niiwoo.civet.account.service.local.refund.newRefund.LanmaoRefundLocalService;
import com.niiwoo.civet.trade.dto.common.BatchTransOrderDetailBizDTO;
import com.niiwoo.civet.trade.dto.common.BatchTransOrderDetailDTO;
import com.niiwoo.civet.trade.dto.common.BatchTransOrderDetailForAccountDTO;
import com.niiwoo.tripod.lanmao.component.LanMaoDirectService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.BusinessTypeEnum;
import com.niiwoo.tripod.lanmao.enums.ResponseCodeEnum;
import com.niiwoo.tripod.lanmao.enums.TradeQueryTypeEnum;
import com.niiwoo.tripod.lanmao.enums.TransactionTypeEnum;
import com.niiwoo.tripod.lanmao.request.QueryTransactionRequest;
import com.niiwoo.tripod.lanmao.response.QueryTransactionResponse;
import com.niiwoo.tripod.provider.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * Created by dell on 2018/1/10.
 */
@Service
@Slf4j
public class QueryRefundTransationLocalService {

    @Autowired
    private LanMaoDirectService lanMaoDirectService;
    @Autowired
    private BatchTransOrderMapperExt batchTransOrderMapperExt;
    @Autowired
    private BatchTransOrderDetailMapperExt batchTransOrderDetailMapperExt;
    @Autowired
    private BatchTransOrderDetailBizMapperExt batchTransOrderDetailBizMapperExt;
    @Autowired
    private CallBackRefundLocalService callBackRefundLocalService;
    @Autowired
    private ProTransactionOrderMapperExt proTransactionOrderMapperExt;
    @Autowired
    private AccountRefundOrderPushDubboService accountRefundOrderPushDubboService;
    @Autowired
    private LanmaoRefundLocalService lanmaoRefundLocalService;
    @Autowired
    private LanMaoSequence lanMaoSequence;


    public void syncTransationStatuAll(String startTime,String endTime){
        log.info("--------syncTransationStatuAll----");

        /**
         * 只关注有冻结成功的记录
         */
        List<ProTransactionOrder> list = proTransactionOrderMapperExt.queryProTransactionOrderNotDelByBatch(startTime,endTime);
        log.info("---syncTransationStatuAll-size={},start--",list.size());
        list.forEach(proTransactionOrder ->{
            try {
                String batchNo = proTransactionOrder.getBatchRequestNo();

                BatchTransOrder batchTransOrder = batchTransOrderMapperExt.selectOrderByBatchRequestNo(proTransactionOrder.getBatchRequestNo());
                if (batchTransOrder == null){
                    log.info("还款批次订单不存在,batchRequestNo={}",batchNo);
                    return;
                }
                //处理中
                if (1 == batchTransOrder.getStatus()){
                    log.info("批次订单状态为处理中,batchNo={}",batchNo);
                    //统计非失败个数据
                    int i = batchTransOrderDetailMapperExt.countSuccessAndHandingNum(batchNo);
                    if (i == 0){
                        //全部失败
                        log.info("批次号对应明细订单全部失败，回滚,batchNo={}",batchNo);
                        RpcContext.getContext().asyncCall(new Runnable() {
                            @Override
                            public void run() {
                                log.info("回滚批次订单batchNo={}",batchNo);
                                if (proTransactionOrder!=null && proTransactionOrder.getId()!=null) {
                                    log.info("回滚批次订单batchNo={},proId={}",batchNo,proTransactionOrder.getId());
                                    accountRefundOrderPushDubboService.rollbackProtransaction(proTransactionOrder.getId());
                                }
                            }
                        });
                        return;
                    }
                    //按批次号处理明细订单
                    syncTransationStatuByBatchNoNew(proTransactionOrder.getBatchRequestNo(),proTransactionOrder.getId());
                }else {
                    log.info("批次batchNO={},状态为{},不处理",batchNo,batchTransOrder.getStatus());
                }
            }catch (Exception e){
                log.error("批次订单号batchNo={},查询存管订单明细失败",proTransactionOrder.getBatchRequestNo(),e);
            }
        });
        log.info("---syncTransationStatuAll-size=,end--");
    }


    public void syncTransationStatuByBatchNoNew(String batchNo,Long proTransOrderId){
        log.info("同步syncTransationStatuByBatchNo={}",batchNo);
        List<BatchTransOrderDetail> batchTransOrderDetailList = batchTransOrderDetailMapperExt.selectByDetailByBatchNo(batchNo);
        log.info("batchTransOrderDetailList={}",batchTransOrderDetailList.size());
        List<AsyncTransactionNotifyDTO> list = new ArrayList<>();
        boolean allSuccess = true;
        for (BatchTransOrderDetail p : batchTransOrderDetailList) {
            AsyncTransactionNotifyDTO dto = new AsyncTransactionNotifyDTO();
            QueryTransactionResponse response = queryTransationConfirm(p.getDetailRequestNo());
            log.info("查询明细数据结果响应respone={},batchNo={}", JSON.toJSONString(response), batchNo);
            //{"code":1,"errorCode":"100007","errorMessage":"该交易不存在! ","status":"INIT","success":false}
            if (response != null) {
                log.info("查询明细订单detailNo={}", p.getDetailRequestNo());
                dto.setAsyncRequestNo(p.getDetailRequestNo());
                dto.setBizType(TransactionTypeEnum.enumOf(p.getTradeType()).name());
                dto.setErrorCode(response.getErrorCode());
                dto.setErrorMessage(response.getErrorMessage());
                if ("100007".equals(response.getErrorCode())) {
                    log.info("明细订单不存在{}", dto.getAsyncRequestNo());
                    dto.setStatus(RefundStatusEnum.FAIL.name());//失败
                    allSuccess = false;
                }
                /**
                 * "code": 0,
                 "records": [{
                 "commission": 0,
                 "confirmTradeType": "REPAYMENT",
                 "createTime": 1520408559000,
                 "projectNo": "10010",
                 "requestNo": "172_21_0_123-8080-60000036302018030715434645",
                 "status": "SUCCESS",
                 "transactionTime": "20180307154243"
                 }],
                 "status": "SUCCESS",
                 "success": true
                 }
                 */
                else if (response.getRecords() != null
                        && response.getRecords().size() > 0
                        && "SUCCESS".equals(response.getRecords().get(0).getStatus())) {
                    log.info("明细成功{}", dto.getAsyncRequestNo());
                    dto.setStatus(RefundStatusEnum.SUCCESS.name());
                } else if (response.getRecords() != null
                        && response.getRecords().size() > 0
                        && "FAIL".equals(response.getRecords().get(0).getStatus())) {
                    dto.setStatus(RefundStatusEnum.FAIL.name());
                    log.info("明细失败{}", dto.getAsyncRequestNo());
                    allSuccess = false;
                } else {
                    dto.setStatus(RefundStatusEnum.HANDLING.name());
                    allSuccess = false;
                }
                list.add(dto);
            }
        }
        //全部成功，且无需更新明细状态，直接走批次成功
        if (allSuccess) {
            Integer handingNum = batchTransOrderDetailMapperExt.countProjectNotSuccessByBatchNo(batchNo);
            if (handingNum == 0) {
                //明细已经全部成功 且本地明细状态都已经更新
                log.info("明细已经全部成功 且明细状态都已经更新,无需更新,batchNo={}", batchNo);
                callBackRefundLocalService.refundCallBackForSuccess(batchNo);
                return;
            }
        }
        log.info("还款回调业务处理服务，需要更新明细状态，batchNO={}", batchNo);
        callBackRefundLocalService.refundCallBack(list);
    }

    public QueryTransactionResponse queryTransation(String requestNo) {
        CompletableFuture<QueryTransactionResponse> future = null;
        QueryTransactionRequest request = new QueryTransactionRequest();
        try {
            // 3.调用银行存款修改标的状态为回款中。
            request.setRequestNo(requestNo);
            request.setTransactionType(TradeQueryTypeEnum.TRANSACTION);
            future = lanMaoDirectService.queryTransaction(request);
        } catch (Throwable e) {
            log.error("调用银行存管查询交易结果异常", e);
            throw new BizException("ACC20009", e.getMessage());
        }

        try {
            log.info("查询请求明细交易状态请求参数{},requestNo={}", JSON.toJSONString(request), requestNo);
            QueryTransactionResponse response = future.get();
            log.info("查询请求明细交易状态响应参数{}，requestNo={}",JSON.toJSONString(response), requestNo);
            if (ResponseCodeEnum.SUCCESS.getValue().equals(response.getCode())) {
                List<QueryTransactionResponse.TransactionDetail> records = response.getRecords();
                if (records == null || records.isEmpty() || records.get(0) == null) {
                    throw new BizException("ACC20009", "调用银行存管查询交易结果失败:" + response.getErrorMessage());
                }
                return response;
            }
        } catch (InterruptedException | ExecutionException e) {
            log.error("查询存管明细交易状态请求异常,requestNo={}",requestNo,e);
        }
        return null;
    }


    /**
     * 交易确认查询接口
     * @param requestNo
     * @return
     */
    public QueryTransactionResponse queryTransationConfirm(String requestNo) {
        CompletableFuture<QueryTransactionResponse> future = null;
        QueryTransactionRequest request = new QueryTransactionRequest();
        try {
            // 3.调用银行存款修改标的状态为回款中。
            request.setRequestNo(requestNo);
            request.setTransactionType(TradeQueryTypeEnum.TRANSACTION);
            future = lanMaoDirectService.queryTransaction(request);
        } catch (Throwable e) {
            log.error("调用银行存管查询交易结果异常", e);

            throw new BizException("ACC20009", e.getMessage());
        }

        try {
            log.info("查询请求明细交易状态请求参数{},requestNo={}", JSON.toJSONString(request), requestNo);
            QueryTransactionResponse response = future.get();
            log.info("查询请求明细交易状态响应参数{}，requestNo={}",JSON.toJSONString(response), requestNo);
            /*if (ResponseCodeEnum.SUCCESS.getValue().equals(response.getCode())) {
                List<QueryTransactionResponse.TransactionDetail> records = response.getRecords();
                if (records == null || records.isEmpty() || records.get(0) == null) {
                    throw new BizException("ACC20009", "调用银行存管查询交易结果失败:" + response.getErrorMessage());
                }

            }*/
            return response;
        } catch (InterruptedException | ExecutionException e) {
            log.error("查询存管明细交易状态请求异常,requestNo={}",requestNo,e);
        }
        return null;
    }

    @Transactional
    public void syncTransationStatuByBatchNoNew(String batchNo) {
        ProTransactionOrder proTransactionOrder = proTransactionOrderMapperExt.queryProTransactionOrderByBatchRequestNo(batchNo);
        Assert.notNull(proTransactionOrder,"预处理订单不存在 ");
        BatchTransOrder batchTransOrder = batchTransOrderMapperExt.selectOrderByBatchRequestNo(batchNo);
        Assert.notNull(batchTransOrder,"还款处理订单不存在 ");
        if (batchTransOrder.getStatus() != 1){
            log.info("状态不是处理中，不处理{}",batchNo);
            return;
        }

        BatchTransOrderDetailForAccountDTO dto = new BatchTransOrderDetailForAccountDTO();
        List<BatchTransOrderDetail> details = batchTransOrderDetailMapperExt.selectByDetailAllByBatchNo(batchNo);
        List<BatchTransOrderDetailDTO> detailOrderDTOs = new ArrayList<>();
        for (BatchTransOrderDetail detail : details) {
            //对失败的重新发送
            if (detail.getStatus() == 3){
                BatchTransOrderDetailDTO detailDTO = new BatchTransOrderDetailDTO();
                detailDTO.setCurrentPeriod(detail.getCurrentPeriod());
                detailDTO.setBatchOrderId(detail.getBatchOrderId());
                detailDTO.setBatchRequestNo(detail.getBatchRequestNo());
                detailDTO.setBorrowUserId(detail.getBorrowUserId());
                detailDTO.setDetailRequestNo(lanMaoSequence.getRequestNo());
                detailDTO.setId(detail.getId());
                detailDTO.setProjectId(detail.getProjectId());
                detailDTO.setTradeTypeStr(TransactionTypeEnum.enumOf(detail.getTradeType()).name());
                detailDTO.setCustomDefine(detail.getCustomDefine());
                log.info("重新处理还款明细old requestNo={},对应new RequestNo={},Json={}",detail.getDetailRequestNo(),detailDTO.getDetailRequestNo(), JSON.toJSONString(detail));

                List<BatchTransOrderDetailBiz> bizs = batchTransOrderDetailBizMapperExt.selectByDetailRequestNo(detail.getDetailRequestNo());
                if (CollectionUtils.isEmpty(bizs)){
                    continue;
                }
                List<BatchTransOrderDetailBizDTO> dtoBizs = new ArrayList<>();
                for (BatchTransOrderDetailBiz biz : bizs) {
                    BatchTransOrderDetailBizDTO bizDTO = new BatchTransOrderDetailBizDTO();
                    bizDTO.setIncome(biz.getInterest().add(biz.getPenaltyFee()));
                    bizDTO.setAmount(biz.getAmount());
                    bizDTO.setBizTypeStr(BusinessTypeEnum.enumOf(biz.getBizType()).name());
                    bizDTO.setCapital(biz.getCapital());
                    bizDTO.setDetailRequestNo(detailDTO.getDetailRequestNo());
                    bizDTO.setExpectInterest(biz.getExpectInterest());
                    bizDTO.setFreezeRequestNo(biz.getFreezeRequestNo());
                    bizDTO.setGuaranteeFee(biz.getGuaranteeFee());
                    bizDTO.setId(biz.getId());
                    bizDTO.setInterest(biz.getInterest());
                    bizDTO.setInvestOrderId(biz.getInvestOrderId());
                    bizDTO.setManageFee(biz.getManageFee());
                    bizDTO.setPenaltyFee(biz.getPenaltyFee());
                    bizDTO.setProxyPretransRequestNo(biz.getProxyPretransRequestNo());
                    bizDTO.setSourceAccountNo(biz.getSourceAccountNo());
                    bizDTO.setTargetAccountNo(biz.getTargetAccountNo());
                    bizDTO.setTransDetailOrderId(biz.getTransDetailOrderId());

                    BatchTransOrderDetailBiz batchTransOrderDetailBizUpdater = new BatchTransOrderDetailBiz();
                    batchTransOrderDetailBizUpdater.setDetailRequestNo(detailDTO.getDetailRequestNo());
                    batchTransOrderDetailBizUpdater.setId(biz.getId());
                    batchTransOrderDetailBizMapperExt.updateByPrimaryKeySelective(batchTransOrderDetailBizUpdater);
                    dtoBizs.add(bizDTO);
                }

                BatchTransOrderDetail batchTransOrderDetailUpdater = new BatchTransOrderDetail();
                batchTransOrderDetailUpdater.setId(detail.getId());
                batchTransOrderDetailUpdater.setStatus(Byte.valueOf("1"));
                batchTransOrderDetailUpdater.setCustomDefine(detail.getDetailRequestNo());
                batchTransOrderDetailUpdater.setDetailRequestNo(detailDTO.getDetailRequestNo());
                batchTransOrderDetailMapperExt.updateByPrimaryKeySelective(batchTransOrderDetailUpdater);
                detailDTO.setBatchTransOrderDetailBizs(dtoBizs);
                detailOrderDTOs.add(detailDTO);
            }
        }
        dto.setBatchTransOrderDetails(detailOrderDTOs);
        String tempBatchNo = new Date().getTime()+"";
        log.info("重发批次号{}",batchNo);
        if ( dto.getBatchTransOrderDetails().size() == 0){
            log.info("数据为空，不重发,batchNo={}",batchNo);
            return;
        }

        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                super.afterCommit();
                log.info("补发订单事物已提交，batchNo={}，新批次号={}",batchNo,tempBatchNo);
                lanmaoRefundLocalService.asyncTransactionForRepeat(dto, tempBatchNo );
            }
        });

    }
}
